﻿using System;

namespace LowLevelGraphics.Types.Predicates
{
    //**************************************************************************
    /// <summary>
    ///    Delegat für boolsche Begingungen z.B. zum Filtern von Elementen
    /// </summary>
    public delegate bool Predicate(Object obj);

    //**************************************************************************
    /// <summary>
    ///    Zur logischen Verknüpfung von Prädikaten
    /// </summary>
    public class Combine
    {
        //-----------------------------------------------------------------------
        Predicate[] _apredToCombine = null;

        //=======================================================================
        /// <summary>
        /// </summary>
        public static Predicate And(params Predicate[] apredToCombine)
        {
            return new Predicate(new Combine(apredToCombine).And);
        }

        //=======================================================================
        /// <summary>
        /// </summary>
        public static Predicate Nand(params Predicate[] apredToCombine)
        {
            return new Predicate(new Combine(
                   new Predicate(new Combine(apredToCombine).And)).Not);
        }

        //=======================================================================
        /// <summary>
        /// </summary>
        public static Predicate Or(params Predicate[] apredToCombine)
        {
            return new Predicate(new Combine(apredToCombine).Or);
        }

        //=======================================================================
        /// <summary>
        /// </summary>
        public static Predicate Nor(params Predicate[] apredToCombine)
        {
            return new Predicate(new Combine(
                   new Predicate(new Combine(apredToCombine).Or)).Not);
        }

        //=======================================================================
        /// <summary>
        /// </summary>
        public static Predicate Xor(params Predicate[] apredToCombine)
        {
            return new Predicate(new Combine(apredToCombine).Xor);
        }

        //=======================================================================
        /// <summary>
        /// </summary>
        public static Predicate Not(Predicate predToCombine)
        {
            return new Predicate(new Combine(predToCombine).Not);
        }

        //=======================================================================
        /// <summary>
        /// </summary>
        protected Combine(params Predicate[] apredToCombine)
        {
            _apredToCombine = apredToCombine;
        }

        //=======================================================================
        /// <summary>
        /// </summary>
        protected bool And(Object obj)
        {
            foreach (Predicate predCurr in _apredToCombine)
            {
                if (!predCurr(obj))
                {
                    return false;
                }
            }
            return true;
        }

        //=======================================================================
        /// <summary>
        /// </summary>
        protected bool Or(Object obj)
        {
            foreach (Predicate predCurr in _apredToCombine)
            {
                if (predCurr(obj))
                {
                    return true;
                }
            }
            return false;
        }

        //=======================================================================
        /// <summary>
        /// </summary>
        protected bool Xor(Object obj)
        {
            bool fResult;

            fResult = false;
            foreach (Predicate predCurr in _apredToCombine)
            {
                fResult = predCurr(obj) != fResult;
            }
            return fResult;
        }

        //=======================================================================
        /// <summary>
        /// </summary>
        protected bool Not(Object obj)
        {
            if (_apredToCombine.Length != 1)
            {
                throw new Exception("Not can only be used for exactly one "
                                   + "predicate");
            }

            return !_apredToCombine[0](obj);
        }
    }
}
